/*
 进行音频采集，采集pcm数据并直接保存pcm数据
 音频参数：
     声道数：        2
     采样位数：    16bit、LE格式
     采样频率：    44100Hz
*/
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <signal.h>
 
FILE *pcm_data_file=NULL;
int run_flag=0;
void exit_sighandler(int sig)
{
    run_flag=1;
}

void help()
{
    printf("./alsatest name rate channel \n");
    printf("eg: \n");
    printf("./alsatest plughw:4,0 48000 1 cc.pcm \n");
}
 
int main(int argc, char *argv[])
{
//    int i;
//    int err;
//    char *buffer;
//    int buffer_frames = 128;
//    unsigned int rate = 44100;// 常用的采样频率: 44100Hz 、16000HZ、8000HZ、48000HZ、22050HZ
//    snd_pcm_t *capture_handle;// 一个指向PCM设备的句柄
//    snd_pcm_hw_params_t *hw_params; //此结构包含有关硬件的信息，可用于指定PCM流的配置
    
    
    if(argc < 4)
    {
        help();
        return 0;
    }

    snd_pcm_t *handle_CAPTURE = NULL;
//    snd_pcm_t *handle_PLAYBACK = NULL;
    char *pcm_name = argv[1];
    int rate = atoi(argv[2]);
    int channels = atoi(argv[3]);
    printf("device_name = %s \n", pcm_name);
    printf("rate        = %d \n", rate);
    printf("channels    = %d \n", channels);
    printf("format      = SND_PCM_FORMAT_FLOAT_LE \n");
    printf("access      = SND_PCM_ACCESS_RW_NONINTERLEAVED \n");
    
    
    
    /*注册信号捕获退出接口*/
    signal(2,exit_sighandler);
    
    
    
    int err = 0;
    err = snd_pcm_open(&handle_CAPTURE, pcm_name, SND_PCM_STREAM_CAPTURE, 0);
    if (err < 0)
    {
        perror("snd_pcm_open CAPTURE");
        return -1;
    }
//    err = snd_pcm_open(&handle_PLAYBACK, "pcm_name", SND_PCM_STREAM_PLAYBACK, 0);
//    if (err < 0)
//    {
//        perror("snd_pcm_open PLAYBACK");
//        return -1;
//    }
    err = snd_pcm_set_params(handle_CAPTURE,
            SND_PCM_FORMAT_FLOAT_LE,
            SND_PCM_ACCESS_RW_INTERLEAVED,
            channels,            //Channels
            rate,               //Rate
            1,            // Allow software resampling
            32000);        // u seconds per buffer
    if (err < 0)
    {
        perror("snd_pcm_set_params CAPTURE");
        return -1;
    }
//    err = snd_pcm_set_params(handle_PLAYBACK,
//            SND_PCM_FORMAT_FLOAT_LE,
//            SND_PCM_ACCESS_RW_NONINTERLEAVED,
//            channels,            //Channels
//            rate,               //Rate
//            1,            // Allow software resampling
//            32000);        // u seconds per buffer
//    if (err < 0)
//    {
//        perror("snd_pcm_set_params CAPTURE");
//        return -1;
//    }
    
    
//
//
//
//
//
//    /*PCM的采样格式在pcm.h文件里有定义*/
//    snd_pcm_format_t format=SND_PCM_FORMAT_S16_LE; // 采样位数：16bit、LE格式
//
//    /*打开音频采集卡硬件，并判断硬件是否打开成功，若打开失败则打印出错误提示*/
//    if ((err = snd_pcm_open (&capture_handle, argv[1],SND_PCM_STREAM_CAPTURE,0))<0)
//    {
//        printf("无法打开音频设备: %s (%s)\n",  argv[1],snd_strerror (err));
//        exit(1);
//    }
//    printf("音频接口打开成功.\n");
 
    /*创建一个保存PCM数据的文件*/
    if((pcm_data_file = fopen(argv[4], "wb")) == NULL)
    {
        printf("无法创建%s音频文件.\n",argv[4]);
        exit(1);
    }
    printf("用于录制的音频文件已打开.\n");
    
    
    
    
//
//    /*分配硬件参数结构对象，并判断是否分配成功*/
//    if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
//    {
//        printf("无法分配硬件参数结构 (%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    printf("硬件参数结构已分配成功.\n");
//
//    /*按照默认设置对硬件对象进行设置，并判断是否设置成功*/
//    if((err=snd_pcm_hw_params_any(capture_handle,hw_params)) < 0)
//    {
//        printf("无法初始化硬件参数结构 (%s)\n", snd_strerror(err));
//        exit(1);
//    }
//    printf("硬件参数结构初始化成功.\n");
//
//    /*
//        设置数据为交叉模式，并判断是否设置成功
//        interleaved/non interleaved:交叉/非交叉模式。
//        表示在多声道数据传输的过程中是采样交叉的模式还是非交叉的模式。
//        对多声道数据，如果采样交叉模式，使用一块buffer即可，其中各声道的数据交叉传输；
//        如果使用非交叉模式，需要为各声道分别分配一个buffer，各声道数据分别传输。
//    */
//    if((err = snd_pcm_hw_params_set_access (capture_handle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
//    {
//        printf("无法设置访问类型(%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    printf("访问类型设置成功.\n");
//
//    /*设置数据编码格式，并判断是否设置成功*/
//    if ((err=snd_pcm_hw_params_set_format(capture_handle, hw_params,format)) < 0)
//    {
//        printf("无法设置格式 (%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    fprintf(stdout, "PCM数据格式设置成功.\n");
//
//    /*设置采样频率，并判断是否设置成功*/
//    if((err=snd_pcm_hw_params_set_rate_near (capture_handle,hw_params,&rate,0))<0)
//    {
//        printf("无法设置采样率(%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    printf("采样率设置成功\n");
//
//    /*设置声道，并判断是否设置成功*/
//    if((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params,1)) < 0)
//    {
//        printf("无法设置声道数(%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    printf("声道数设置成功.\n");
//
//    /*将配置写入驱动程序中，并判断是否配置成功*/
//    if ((err=snd_pcm_hw_params (capture_handle,hw_params))<0)
//    {
//        printf("无法向驱动程序设置参数(%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    printf("参数设置成功.\n");
//
//    /*使采集卡处于空闲状态*/
//    snd_pcm_hw_params_free(hw_params);
//
//    /*准备音频接口,并判断是否准备好*/
//    if((err=snd_pcm_prepare(capture_handle))<0)
//    {
//        printf("无法使用音频接口 (%s)\n",snd_strerror(err));
//        exit(1);
//    }
//    printf("音频接口准备好.\n");
//
//    /*配置一个数据缓冲区用来缓冲数据*/
//    buffer=malloc(128*snd_pcm_format_width(format)/8*2);
//    printf("缓冲区分配成功.\n");
//
//    /*开始采集音频pcm数据*/
//    printf("开始采集数据...\n");
//    while(1)
//    {
//        /*从声卡设备读取一帧音频数据*/
//        if((err=snd_pcm_readi(capture_handle,buffer,buffer_frames))!=buffer_frames)
//        {
//              printf("从音频接口读取失败(%s)\n",snd_strerror(err));
//              exit(1);
//        }
//        /*写数据到文件*/
//        fwrite(buffer,(buffer_frames*2),sizeof(short),pcm_data_file);
//
//        if(run_flag)
//        {
//            printf("停止采集.\n");
//            break;
//        }
//    }
    
    int rc = 0;
    int i = 0;
    void *bufs[channels];
    while (1)
    {
        int bitByte = 1;
        snd_pcm_sframes_t frames = 480;
        float pcm[bitByte * frames * channels];
        
        for(i=0;i<channels;++i)
        {
            bufs[i] = pcm + (bitByte * frames * i);
        }
        rc = snd_pcm_readn(handle_CAPTURE, bufs, frames);
        
        fwrite(bufs,(frames*2),sizeof(float),pcm_data_file);
        if (rc == -EPIPE)
        {
            snd_pcm_prepare(handle_CAPTURE);
        }
        else if (rc != frames)
        {
            printf("CAPTURE snd_pcm_readn miss %d \n", rc);
        }
//        rc = snd_pcm_writen(handle_PLAYBACK, bufs, frames);
//        if (rc == -EPIPE)
//        {
//            snd_pcm_prepare(handle_PLAYBACK);
//        }
//        else if (rc != frames)
//        {
//            printf("PLAYBACK snd_pcm_readn miss %d \n", rc);
//        }
//
        printf("采集中......\n");
        if(run_flag)
        {
            printf("停止采集.\n");
            break;
        }
    }
 
    /*释放数据缓冲区*/
    free(bufs);
 
    /*关闭音频采集卡硬件*/
    snd_pcm_close(handle_CAPTURE);
 
    /*关闭文件流*/
    fclose(pcm_data_file);
    return 0;
}
 


